/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.framework;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.aop.Advisor;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.SmartClassLoader;
import org.springframework.lang.Nullable;

/**
 * Base class for {@link BeanPostProcessor} implementations that apply a
 * Spring AOP {@link Advisor} to specific beans.
 *
 * @author Juergen Hoeller
 * @since 3.2
 */
/*
1.  总结 专注于将指定的Advisor应用到符合条件的Bean上。
	抽象Bean后置处理器 - 为Spring AOP中应用Advisor到特定Bean的BeanPostProcessor实现提供抽象基类
	Advisor管理 - 提供统一的Advisor应用机制，支持在现有通知之前或之后添加Advisor
	智能代理创建 - 自动判断Bean是否需要代理，并根据需要创建合适的代理对象
2. 内部成员详解
	成员变量:
		advisor: Advisor，要应用到Bean的Advisor
		beforeExistingAdvisors: boolean，是否在现有Advisor之前应用
		eligibleBeans: Map<Class<?>, Boolean>，Bean适配性缓存
	核心方法:
		setBeforeExistingAdvisors() - 设置是否在现有Advisor之前应用
		postProcessAfterInitialization() - 核心后置处理方法，应用Advisor到Bean
		isEligible(Object bean, String beanName) - 检查Bean是否适合应用Advisor
		isEligible(Class<?> targetClass) - 检查类是否适合应用Advisor，带缓存
		prepareProxyFactory() - 准备ProxyFactory实例
		customizeProxyFactory() - 自定义ProxyFactory的钩子方法
3. 类关系结构
ProxyConfig (class)
└── ProxyProcessorSupport (class)
    └── AbstractAdvisingBeanPostProcessor (abstract class) 自定义AOP代理（ 将Advisor应用到符合条件的Bean提供基础框架）
        └── AbstractBeanFactoryAwareAdvisingPostProcessor (abstract class)	在AbstractAdvisingBeanPostProcessor基础上增加BeanFactory感知能力
            └── MethodValidationPostProcessor (class) 方法参数和返回值验证 （专门用于方法级别验证的AOP处理器，为带有@Validated注解的Bean添加方法验证功能）
            └── PersistenceExceptionTranslationPostProcessor (class)  持久化异常转换，专门处理持久化层异常转换（将底层持久化框架的异常（如SQLException）转换为Spring的统一数据访问异常）
            └── AsyncAnnotationBeanPostProcessor (class)	异步方法处理（为带有@Async注解的方法创建异步代理）
相关类关系说明:
	ProxyProcessorSupport: 父类，提供通用的代理处理器功能
	BeanPostProcessor: 实现此接口以参与Bean的后置处理
	Advisor: 要应用到Bean的通知器
	ProxyFactory: 用于创建代理对象
	AbstractBeanFactoryAwareAdvisingPostProcessor: 直接子类，增加了BeanFactory感知能力
	MethodValidationPostProcessor: 具体实现类，用于方法验证
	AbstractAdvisingBeanPostProcessor专注于将特定Advisor应用到符合条件的Bean上。

	AbstractAdvisingBeanPostProcessor（抽象通知应用Bean后置处理器）
		核心功能
			为特定Bean应用单个指定的Advisor
			判断Bean是否需要代理
			为需要代理的Bean创建AOP代理

	AbstractBeanFactoryAwareAdvisingPostProcessor（BeanFactory感知通知应用处理器）
		核心功能
		在AbstractAdvisingBeanPostProcessor基础上增加BeanFactory感知能力
		提供更灵活的Advisor获取机制
		支持基于BeanFactory的条件判断

	PersistenceExceptionTranslationPostProcessor（持久化异常转换后置处理器）
		核心功能
		为带有@Repository注解的Bean添加持久化异常转换功能
		将底层持久化框架异常转换为Spring统一的DataAccessException


	MethodValidationPostProcessor（方法验证后置处理器）
		核心功能
		为带有@Validated注解的Bean添加方法级验证功能
		集成Bean Validation API进行参数和返回值验证

AbstractAdvisingBeanPostProcessor 和 AbstractAutoProxyCreator 区别

	AbstractAdvisingBeanPostProcessor
		定位：为特定Bean应用单个指定Advisor的处理器
		目标：将一个预定义的Advisor应用到符合条件的Bean上
		粒度：一对一或一对多（一个Advisor对多个Bean）
		简单直接：预定义Advisor，逻辑清晰
		性能较好：不需要动态查找Advisor
		灵活性有限：只能应用预设的单一Advisor
	AbstractAutoProxyCreator
】		定位：自动发现并应用多个Advisor的代理创建器
		目标：自动为Bean匹配和应用所有适用的Advisor
		粒度：多对多（多个Advisor对多个Bean）
		高度灵活：动态匹配多个Advisor
		功能强大：支持复杂的切面匹配逻辑
		复杂度高：需要实现Advisor发现和匹配逻辑
		性能开销：每次都需要查找适用的Advisor
		Advisor是动态发现的多个实例
		通过getAdvicesAndAdvisorsForBean抽象方法由子类实现获取
		为每个Bean单独查找适用的Advisor集合

4. 使用场景
	特定Advisor应用 - 将特定的Advisor应用到符合条件的Bean集合
	自定义AOP处理 - 开发自定义的AOP Bean后置处理器
	框架扩展 - 作为Spring AOP框架扩展的基础类
	条件性代理 - 根据特定条件为Bean创建代理
5. 实际代码应用示例
=================案例1 自定义Advisor应用处理器:
public class CustomAdvisingBeanPostProcessor extends AbstractAdvisingBeanPostProcessor {

    public CustomAdvisingBeanPostProcessor() {
        // 设置要应用的Advisor
        this.advisor = new DefaultPointcutAdvisor(
            new AnnotationMatchingPointcut(CustomAnnotation.class),
            new CustomMethodInterceptor()
        );
        // 设置在现有Advisor之前应用
        this.beforeExistingAdvisors = true;
    }

    @Override
    protected boolean isEligible(Object bean, String beanName) {
        // 自定义适配性检查逻辑
        return bean.getClass().getName().startsWith("com.example.service");
    }
}



 */
@SuppressWarnings("serial")
public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSupport implements BeanPostProcessor {

	@Nullable
	protected Advisor advisor;

	protected boolean beforeExistingAdvisors = false;

	private final Map<Class<?>, Boolean> eligibleBeans = new ConcurrentHashMap<>(256);


	/**
	 * Set whether this post-processor's advisor is supposed to apply before
	 * existing advisors when encountering a pre-advised object.
	 * <p>Default is "false", applying the advisor after existing advisors, i.e.
	 * as close as possible to the target method. Switch this to "true" in order
	 * for this post-processor's advisor to wrap existing advisors as well.
	 * <p>Note: Check the concrete post-processor's javadoc whether it possibly
	 * changes this flag by default, depending on the nature of its advisor.
	 */
	public void setBeforeExistingAdvisors(boolean beforeExistingAdvisors) {
		this.beforeExistingAdvisors = beforeExistingAdvisors;
	}


	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (this.advisor == null || bean instanceof AopInfrastructureBean) {
			// Ignore AOP infrastructure such as scoped proxies.
			return bean;
		}

		if (bean instanceof Advised) {
			Advised advised = (Advised) bean;
			if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
				// Add our local Advisor to the existing proxy's Advisor chain...
				if (this.beforeExistingAdvisors) {
					advised.addAdvisor(0, this.advisor);
				}
				else {
					advised.addAdvisor(this.advisor);
				}
				return bean;
			}
		}

		if (isEligible(bean, beanName)) {
			ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
			if (!proxyFactory.isProxyTargetClass()) {
				evaluateProxyInterfaces(bean.getClass(), proxyFactory);
			}
			proxyFactory.addAdvisor(this.advisor);
			customizeProxyFactory(proxyFactory);

			// Use original ClassLoader if bean class not locally loaded in overriding class loader
			ClassLoader classLoader = getProxyClassLoader();
			if (classLoader instanceof SmartClassLoader && classLoader != bean.getClass().getClassLoader()) {
				classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
			}
			return proxyFactory.getProxy(classLoader);
		}

		// No proxy needed.
		return bean;
	}

	/**
	 * Check whether the given bean is eligible for advising with this
	 * post-processor's {@link Advisor}.
	 * <p>Delegates to {@link #isEligible(Class)} for target class checking.
	 * Can be overridden e.g. to specifically exclude certain beans by name.
	 * <p>Note: Only called for regular bean instances but not for existing
	 * proxy instances which implement {@link Advised} and allow for adding
	 * the local {@link Advisor} to the existing proxy's {@link Advisor} chain.
	 * For the latter, {@link #isEligible(Class)} is being called directly,
	 * with the actual target class behind the existing proxy (as determined
	 * by {@link AopUtils#getTargetClass(Object)}).
	 * @param bean the bean instance
	 * @param beanName the name of the bean
	 * @see #isEligible(Class)
	 */
	protected boolean isEligible(Object bean, String beanName) {
		return isEligible(bean.getClass());
	}

	/**
	 * Check whether the given class is eligible for advising with this
	 * post-processor's {@link Advisor}.
	 * <p>Implements caching of {@code canApply} results per bean target class.
	 * @param targetClass the class to check against
	 * @see AopUtils#canApply(Advisor, Class)
	 */
	protected boolean isEligible(Class<?> targetClass) {
		Boolean eligible = this.eligibleBeans.get(targetClass);
		if (eligible != null) {
			return eligible;
		}
		if (this.advisor == null) {
			return false;
		}
		eligible = AopUtils.canApply(this.advisor, targetClass);
		this.eligibleBeans.put(targetClass, eligible);
		return eligible;
	}

	/**
	 * Prepare a {@link ProxyFactory} for the given bean.
	 * <p>Subclasses may customize the handling of the target instance and in
	 * particular the exposure of the target class. The default introspection
	 * of interfaces for non-target-class proxies and the configured advisor
	 * will be applied afterwards; {@link #customizeProxyFactory} allows for
	 * late customizations of those parts right before proxy creation.
	 * @param bean the bean instance to create a proxy for
	 * @param beanName the corresponding bean name
	 * @return the ProxyFactory, initialized with this processor's
	 * {@link ProxyConfig} settings and the specified bean
	 * @since 4.2.3
	 * @see #customizeProxyFactory
	 */
	protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);
		proxyFactory.setTarget(bean);
		return proxyFactory;
	}

	/**
	 * Subclasses may choose to implement this: for example,
	 * to change the interfaces exposed.
	 * <p>The default implementation is empty.
	 * @param proxyFactory the ProxyFactory that is already configured with
	 * target, advisor and interfaces and will be used to create the proxy
	 * immediately after this method returns
	 * @since 4.2.3
	 * @see #prepareProxyFactory
	 */
	protected void customizeProxyFactory(ProxyFactory proxyFactory) {
	}

}
